<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>🎙️ 语音对话（后端识别）</title>
    <style>
        body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }
        button { padding: 12px 24px; font-size: 18px; margin: 10px; cursor: pointer; }
        #log { margin: 20px; padding: 10px; background: #f4f4f4; border-radius: 5px; min-height: 100px; }
    </style>
</head>
<body>
<h1>🎙️ 语音对话（后端处理）</h1>
<button id="startBtn">🟢 开始录音</button>
<button id="stopBtn" disabled>🔴 停止</button>
<div id="log">等待连接...</div>
<audio id="audioPlayer" controls style="display:none;"></audio>

<script>
    const startBtn = document.getElementById('startBtn');
    const stopBtn = document.getElementById('stopBtn');
    const logDiv = document.getElementById('log');
    const audioPlayer = document.getElementById('audioPlayer');

    let ws = null;
    let mediaRecorder = null;
    let audioChunks = [];

    function log(msg) {
        const el = document.createElement('div');
        el.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
        logDiv.appendChild(el);
        logDiv.scrollTop = logDiv.scrollHeight;
    }

    // 连接 WebSocket
    function connect() {
        ws = new WebSocket(`ws://localhost:18881/ws/voice`);
        ws.binaryType = 'arraybuffer';

        ws.onopen = () => {
            log('已连接到服务器');
        };

        ws.onmessage = (event) => {
            const data = JSON.parse(event.data);
            if (data.type === 'audio') {
                const audioBlob = base64ToBlob(data.data, 'audio/mp3');
                const url = URL.createObjectURL(audioBlob);
                audioPlayer.src = url;
                audioPlayer.onended = () => URL.revokeObjectURL(url);
                audioPlayer.play();
                log('播放回复语音');
            }
        };

        ws.onclose = () => {
            log('连接已关闭，重连中...');
            setTimeout(connect, 3000);
        };

        ws.onerror = (err) => log('WebSocket 错误');
    }

    function base64ToBlob(base64, mimeType) {
        const byteString = atob(base64);
        const arrayBuffer = new ArrayBuffer(byteString.length);
        const int8Array = new Uint8Array(arrayBuffer);
        for (let i = 0; i < byteString.length; i++) {
            int8Array[i] = byteString.charCodeAt(i);
        }
        return new Blob([arrayBuffer], { type: mimeType });
    }

    startBtn.onclick = async () => {
        try {
            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
            mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm;codecs=opus' });

            mediaRecorder.ondataavailable = (e) => {
                console.log('chunk size:', e.data.size);
                if (e.data.size > 0) {
                    audioChunks.push(e.data);
                }
            };

            mediaRecorder.onstop = () => {
                const blob = new Blob(audioChunks, { type: 'audio/webm' });
                // const reader = new FileReader();
                // reader.onload = () => {
                //     console.log('准备发送音频，字节数：', reader.result.byteLength);
                //     console.log('ws.readyState:', ws.readyState);
                //     ws.send(reader.result); // ArrayBuffer
                //     log('音频已发送');
                // };
                // reader.readAsArrayBuffer(blob);
                ws.send(blob);
                audioChunks = [];
            };

            mediaRecorder.start();
            startBtn.disabled = true;
            stopBtn.disabled = false;
            log('正在录音...');
        } catch (err) {
            log('无法访问麦克风: ' + err.message);
        }
    };

    stopBtn.onclick = () => {
        if (mediaRecorder && mediaRecorder.state !== "inactive") {
            mediaRecorder.stop();
            mediaRecorder.stream.getTracks().forEach(t => t.stop());
            startBtn.disabled = false;
            stopBtn.disabled = true;
        }
    };

    window.onload = connect;
</script>
</body>
</html>